﻿using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using RedLockNet.SERedis;
using RedLockNet.SERedis.Configuration;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Runtime.Serialization;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using Tsual.Util;
using Tsual.Util.Redis;
using Tsual.Wechat.Cache;
using Tsual.Wechat.Message;
using Tsual.Wechat.Message.Exceptions;
using Tsual.Wechat.Message.Impl;
using Tsual.Wechat.Message.Impl.Internal;
using Tsual.Wechat.Message.Impl.Response;
using Tsual.Wechat.Message.Interface.Request;
using Tsual.Wechat.Message.Interface.Response;
using System.Web;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Configuration;
using Microsoft.AspNetCore.Mvc;
using System.Xml.Linq;
using System.Net;
using System.Collections;
using Tsual.Wechat;
using Tsual.Wechat.Formatters;
using Microsoft.AspNetCore.Hosting;
using Tsual.Wechat.Enums;
using Microsoft.Extensions.Hosting;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Tsual.Wechat.Filters;
using System.Reflection;
using Tsual.Wechat.Controllers;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.Extensions.Options;


namespace Tsual.Wechat.Message.Impl.Response
{
    public class WechatResponseText : IWechatResponseText
    {
        public string Content { get; set; }
        public string ToUserName { get; set; }
        public string FromUserName { get; set; }
        public int CreateTime { get; set; }
    }

    internal class WechatResponseTimeoutText : IWechatResponseText
    {
        public string Content { get; set; }
        public string ToUserName { get; set; }
        public string FromUserName { get; set; }
        public int CreateTime { get; set; }
    }

    public class WechatResponseImage : IWechatResponseImage
    {
        public string MediaId { get; set; }
        public string ToUserName { get; set; }
        public string FromUserName { get; set; }
        public int CreateTime { get; set; }
    }

    public class WechatResponseVoice : IWechatResponseVoice
    {
        public string MediaId { get; set; }
        public string ToUserName { get; set; }
        public string FromUserName { get; set; }
        public int CreateTime { get; set; }
    }

    public class WechatResponseVideo : IWechatResponseVideo
    {
        public string Title { get; set; }
        public string Description { get; set; }
        public string MediaId { get; set; }
        public string ToUserName { get; set; }
        public string FromUserName { get; set; }
        public int CreateTime { get; set; }
    }

    public class WechatResponseMusic : IWechatResponseMusic
    {
        public string Title { get; set; }
        public string Description { get; set; }
        public string MusicUrl { get; set; }
        public string HQMusicUrl { get; set; }
        public string ThumbMediaId { get; set; }
        public string ToUserName { get; set; }
        public string FromUserName { get; set; }
        public int CreateTime { get; set; }
    }

    public class WechatResponseNews : IWechatResponseNews
    {
        public int ArticleCount { get; set; }
        public IEnumerable<IWechatResponseArticleItem> Articles { get; set; } = new HashSet<IWechatResponseArticleItem>();
        public string ToUserName { get; set; }
        public string FromUserName { get; set; }
        public int CreateTime { get; set; }
    }
}

namespace Tsual.Wechat.Menu.Model
{
    public class WechatMenuRoot
    {
        public List<WechatMenuItem> button { get; } = new List<WechatMenuItem>();
    }

    public abstract class WechatMenuItem { }

    public class WechatView : WechatMenuItem
    {
        public string type { get; } = "view";
        public string name { get; set; }
        public string url { get; set; }
    }

    public class WechatSubmenu : WechatMenuItem
    {
        public string name { get; set; }
        public List<WechatMenuItem> sub_button { get; } = new List<WechatMenuItem>();
    }
}

namespace Tsual.Wechat.Message.Impl
{
    public abstract class AbstractWechatServerResponseModel { }
    public class BasicWechatServerResponseModel : AbstractWechatServerResponseModel
    {
        public int errcode { get; set; }
        public string errmsg { get; set; }

        public void ThrowException()
        {
            if (errcode != 0) throw new WechatApiException(string.Format("微信API返回错误 code:{0} msg:{1}", errcode, errmsg)) { Response = this };
        }

        public static async Task<T> PackageServerReturnFromHttpResponseAsync<T>(HttpResponseMessage response, string friendMessage = null, ILogger logger = null) where T : BasicWechatServerResponseModel
        {
            T rtn = null;
            if (response.IsSuccessStatusCode)
            {
                rtn = JsonConvert.DeserializeObject<T>(await response.Content.ReadAsStringAsync());
                rtn.ThrowException();
                return rtn;
            }
            else
            {
                var message = string.IsNullOrEmpty(friendMessage) ? $"请求微信服务器失败，返回:{response}" : $"{friendMessage} 出错:{response}";
                logger?.LogError(message);
                throw new WechatApiException(message) { Response = rtn };
            }
        }
    }
    public class WsrmAccessToken : BasicWechatServerResponseModel
    {
        public string access_token { get; set; }
        public int expires_in { get; set; }

    }
    public class WsrmUserAccessToken : WsrmAccessToken
    {
        public string refresh_token { get; set; }
        public string openid { get; set; }
        public string scope { get; set; }
    }
    public class WsrmServerAddressList : BasicWechatServerResponseModel
    {
        public string[] ip_list { get; set; }
    }
    /// <summary>
    /// 我是没想通微信接口定义人的脑子是不是有问题
    /// </summary>
    public class WssmCompanyTradePost : BasicWechatServerResponseModel
    {
        public string industry_id1 { get; set; }
        public string industry_id2 { get; set; }
        public WechatCompanyTradeEnum PrimaryIndeustry { get => (WechatCompanyTradeEnum)int.Parse(industry_id1); set => industry_id1 = ((int)value).ToString(); }
        public WechatCompanyTradeEnum SecondaryIndeustry { get => (WechatCompanyTradeEnum)int.Parse(industry_id2); set => industry_id2 = ((int)value).ToString(); }
    }
    /// <summary>
    /// 我是没想通微信接口定义人的脑子是不是有问题
    /// </summary>
    public class WsrmCompanyTradeQuery : BasicWechatServerResponseModel
    {
        public WsrmCompanyTradeQueryItem primary_industry { get; set; }
        public WsrmCompanyTradeQueryItem secondary_industry { get; set; }
    }
    /// <summary>
    /// 我是没想通微信接口定义人的脑子是不是有问题
    /// </summary>
    public class WsrmCompanyTradeQueryItem
    {
        public string first_class { get; set; }
        public string second_class { get; set; }
    }
    public class WsrmTemplateId : BasicWechatServerResponseModel
    {
        public string template_id { get; set; }
    }
    public class WsrmTemplateList : BasicWechatServerResponseModel
    {
        public WsrmTemplateListItem[] template_list { get; set; }
    }
    public class WsrmTemplateListItem
    {
        public string template_id { get; set; }
        public string title { get; set; }
        public string primary_industry { get; set; }
        public string deputy_industry { get; set; }
        public string content { get; set; }
        public string example { get; set; }
    }
    public class WssmTemplateSend
    {
        public string touser { get; set; }
        public string template_id { get; set; }
        public string url { get; set; }
        public string miniprogram { get; set; }
        /// <summary>
        /// donot set
        /// </summary>
        public string appid { get; set; }
        public string pagepath { get; set; }
        public Dictionary<string, WssmTemplateSendItem> data { get; set; }
    }
    public class WssmTemplateSendItem
    {
        public string value { get; set; }
        public string color { get; set; }
    }
    public class WsrmMessageid : BasicWechatServerResponseModel
    {
        public int msgid { get; set; }
    }
    public class WsrmUsers : BasicWechatServerResponseModel
    {
        public ulong total { get; set; }
        public int count { get; set; }
        /// <summary>
        /// 最后一个！！！！不是下一个  别问我为什么这个搞 问腾讯
        /// </summary>
        public string next_openid { get; set; }
        /// <summary>
        /// 这么蠢的数据结构
        /// </summary>
        public WsrmUsersData data { get; set; }
    }
    public class WsrmUsersData
    {
        public string[] openid { get; set; }
    }
    public class WsrmUserTags : BasicWechatServerResponseModel
    {
        public WsrmUserTagsItem[] tags { get; set; }
    }
    public class WsrmUserTagsItem
    {
        public int id { get; set; }
        public string name { get; set; }
        public long count { get; set; }

        public static explicit operator KeyValuePair<string, string>(WsrmUserTagsItem obj) => new KeyValuePair<string, string>(obj.name, $"{obj.id}_{obj.count}");
        public static explicit operator WsrmUserTagsItem(KeyValuePair<string, string> pair)
        {
            var ll = pair.Value.Split('_').Select(t => int.Parse(t)).ToArray();
            return new WsrmUserTagsItem()
            {
                id = ll[0],
                name = pair.Key,
                count = ll[1]
            };
        }
    }
}

namespace Tsual.Wechat.Message.Impl.Internal
{
    internal class WechatMessageRequestModel : AbstractWechatServerResponseModel, IWechatMessageRequestModel
    {
        public string MsgType { get; set; }
        public string ToUserName { get; set; }
        public string FromUserName { get; set; }
        public int CreateTime { get; set; }
        public ulong MsgId { get; set; }
        public string Content { get; set; }
        public string MediaId { get; set; }
        public string ThumbMediaId { get; set; }
        public string PicUrl { get; set; }
        public string Format { get; set; }
        public string Recognition { get; set; }
        public double Location_X { get; set; }
        public double Location_Y { get; set; }
        public double Scale { get; set; }
        public string Label { get; set; }
        public string Title { get; set; }
        public string Description { get; set; }
        public string Url { get; set; }
        public string Event { get; set; }
        public string EventKey { get; set; }
        public string Ticket { get; set; }
        public double Latitude { get; set; }
        public double Longitude { get; set; }
        public double Precision { get; set; }

        WechatRequestMsgTypes IWechatHandlableMessageRequest.MessagesType => (WechatRequestMsgTypes)Enum.Parse(typeof(WechatRequestMsgTypes), MsgType);
    }
}

namespace Tsual.Wechat.Enums
{
    public enum WechatCompanyTradeEnum
    {
        IT科技_互联网_电子商务 = 1,
        IT科技_IT软件与服务 = 2,
        IT科技_IT硬件与设备 = 3,
        IT科技_电子技术 = 4,
        IT科技_通信与运营商 = 5,
        IT科技_网络游戏 = 6,
        金融业_银行 = 7,
        金融业_基金理财信托 = 8,
        金融业_保险 = 9,
        餐饮_餐饮 = 10,
        酒店旅游_酒店 = 11,
        酒店旅游_旅游 = 12,
        运输与仓储_快递 = 13,
        运输与仓储_物流 = 14,
        运输与仓储_仓储 = 15,
        教育_培训 = 16,
        教育_院校 = 17,
        政府与公共事业_学术科研 = 18,
        政府与公共事业_交警 = 19,
        政府与公共事业_博物馆 = 20,
        政府与公共事业_公共事业非盈利机构 = 21,
        医药护理_医药医疗 = 22,
        医药护理_护理美容 = 23,
        医药护理_保健与卫生 = 24,
        交通工具_汽车相关 = 25,
        交通工具_摩托车相关 = 26,
        交通工具_火车相关 = 27,
        交通工具_飞机相关 = 28,
        房地产_建筑 = 29,
        房地产_物业 = 30,
        消费品_消费品 = 31,
        商业服务_法律 = 32,
        商业服务_会展 = 33,
        商业服务_中介服务 = 34,
        商业服务_认证 = 35,
        商业服务_审计 = 36,
        文体娱乐_传媒 = 37,
        文体娱乐_体育 = 38,
        文体娱乐_娱乐休闲 = 39,
        印刷_印刷 = 40,
        其它_其它 = 41,
    }
}

namespace Tsual.Wechat.Cache
{
    public enum WechatCacheKeyEnum
    {
        /// <summary>
        /// APP ACCESS_TOKEN string
        /// </summary>
        ACCESS_TOKEN = 1,
        /// <summary>
        /// User ACCESS_TOKEN hash
        /// </summary>
        USER_ACCESS_TOKEN,
        /// <summary>
        /// User REFRESH_TOKEN hash
        /// </summary>
        USER_REFRESH_TOKEN,
        /// <summary>
        /// 页面访问缓存，排重用途 hash
        /// </summary>
        USER_ACCESS_PAGE_CODE,
        /// <summary>
        /// 已经绑定的用户 hash
        /// </summary>
        USER_KNOWN,
        /// <summary>
        /// 用户并发操作锁 redlock
        /// </summary>
        USER_OPERATION_LOCK,
        /// <summary>
        /// 微信服务器地址 set
        /// </summary>
        SERVER_ADDRESS,
        /// <summary>
        /// 所有微信用户 set
        /// </summary>
        ALL_USERS,
        /// <summary>
        /// 用户标签 hash
        /// </summary>
        USER_TAG,
    }

    public static class WechatCacheExtensions
    {
        public static string ToRedisKey(this WechatCacheKeyEnum keyEnum) => $"{WechatContext.Instance.CacheHead}:WECHAT:{keyEnum}";
    }
}

namespace Tsual.Wechat.Message.Exceptions
{
    public class WechatApiException : Exception
    {
        public BasicWechatServerResponseModel Response { get; set; }

        public WechatApiException()
        {
        }

        public WechatApiException(string message) : base(message)
        {
        }

        public WechatApiException(string message, Exception innerException) : base(message, innerException)
        {
        }

        protected WechatApiException(SerializationInfo info, StreamingContext context) : base(info, context)
        {
        }
    }
}